package com.swan.web.exception;

import com.swan.web.auto.config.WebConfig;
import com.swan.web.domain.BaseResponse;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.OrderComparator;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

/** 默认全局异常处理, 如果不启用时，设置 swan.web.exception.enable=false
 * @author zongf
 * @since 2021-08-16
 */
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {

    protected LinkedHashMap<Class<? extends Throwable>, IExceptionHandler> exceptionHandlerMap = new LinkedHashMap<>();

    @Autowired(required = false)
    private IUnknownExceptionHandler unknownExceptionHandler;

    @Autowired
    private WebConfig webConfig;

    public GlobalExceptionHandler(List<IExceptionHandler> exceptionHandlers) {
        OrderComparator.sort(exceptionHandlers);
        for (IExceptionHandler exceptionHandler : exceptionHandlers) {
            exceptionHandlerMap.put(exceptionHandler.handleType(), exceptionHandler);
        }
    }

    @ExceptionHandler(Throwable.class)
    public BaseResponse catchThrowable(HttpServletResponse response, Throwable throwable) {

        IExceptionHandler exceptionHandler = getExceptionHandler(throwable.getClass());

        if (exceptionHandler == null) {
            return new BaseResponse(webConfig.getException().getUnknownCode(), webConfig.getException().getUnknownMessage());
        }

        response.setStatus(exceptionHandler.httpStatus());

        return exceptionHandler.handle(throwable);
    }

    private IExceptionHandler getExceptionHandler(Class<? extends Throwable> exceptionClz) {
        IExceptionHandler thriftExceptionHandler = exceptionHandlerMap.get(exceptionClz);

        if (thriftExceptionHandler == null) {
            Map.Entry<Class<? extends Throwable>, IExceptionHandler> handlerEntry = exceptionHandlerMap.entrySet().stream()
                    .filter(entry -> entry.getKey().isAssignableFrom(exceptionClz))
                    .findAny()
                    .get();

            if (handlerEntry != null) {
                thriftExceptionHandler = handlerEntry.getValue();
            }
        }

        // 如果没有匹配到拦截器
        if (thriftExceptionHandler == null) {
            thriftExceptionHandler = unknownExceptionHandler;
        }

        return thriftExceptionHandler;
    }



}
